﻿#region Copyright Notice
// This file is part of GestionPedago.
// <description>
// Copyright (C) 2012 ENI Ecole Informatique
// 
// GestionPedago is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// <program> is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GestionPedago.EntityContext;
using GestionPedago.EntityContext.EntityOPTools;
using System.Data;

namespace GestionPedago.Persistence.OPManager
{
    /// <summary>
    /// Manager de persistance de l'entity Alerte
    /// </summary>
    public abstract class AlerteOPManager
    {
        /// <summary>
        /// Méthode de génération des alertes automatiques
        /// </summary>
        /// <returns>La liste d'alertes</returns>
        public static List<Alerte> GenereAlertes()
        {
            try
            {
                List<Alerte> lst = new List<Alerte>();
                lst.AddRange(GenereAlertesDelaiCorrectionECF());
                lst.AddRange(GenereAlertesECFNonPlanifiesPourCompetences());
                lst.AddRange(GenereAlertesPertinencePlanificationsECF());
                return lst;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// Méthode qui génère les alertes liées à la pertinence des planifications d'ECF
        /// </summary>
        /// <returns>La liste d'alerte</returns>
        public static List<Alerte> GenereAlertesPertinencePlanificationsECF()
        {
            List<Alerte> lst = new List<Alerte>();
            IQueryable<PlanningECFDetail> query = EntityConnection.GetContext().PlanningECFDetail;
            query = query.Where(it => it.PlanningECF.DateECF >= DateTime.Now);
            List<PlanningECFDetail> listePlanningECFDetail = query.ToList();
            foreach(PlanningECFDetail ped in listePlanningECFDetail)
            {
                PlanningIndividuelFormation pif = ped.PlanningIndividuelFormation;
                IQueryable<PlanningIndividuelDetail> queryPid = EntityConnection.GetContext().PlanningIndividuelDetail;
                queryPid = queryPid.Where(it => it.CodePlanning == pif.CodePlanning);
                queryPid = queryPid.OrderByDescending(it => it.FinCours);
                bool testFait = false;
                List<PlanningIndividuelDetail> listePlanningIndividuelDetail = queryPid.ToList();
                foreach (PlanningIndividuelDetail pid in listePlanningIndividuelDetail)
                {
                    ModuleParECF mpe = new ModuleParECF();
                    mpe.IdModule = pid.Cours.Module.IdModule;
                    if (ped.PlanningECF.ECF.ModuleParECF.Contains(mpe, new ModuleParECFComparerOnModule()) && testFait == false)
                    {
                        if (pid.Cours.Fin > ped.PlanningECF.DateECF)
                        {
                            Alerte a = new Alerte();
                            a.DateAlerte = DateTime.Now;
                            a.Echeance = DateTime.Now;
                            a.IdTypeAlerte = 1;
                            a.Actif = true;
                            a.Message = "La planification de l'ECF " + ped.PlanningECF.ECF.Libelle + " pour le stagiaire " + pid.PlanningIndividuelFormation.Stagiaire.Prenom + " " + pid.PlanningIndividuelFormation.Stagiaire.Nom + " à la date " + ped.PlanningECF.DateECF + " est antérieure à la fin du cours du dernier module prérequis (" + pid.Cours.Module.Libelle + ")";
                            lst.Add(a);
                        }
                        testFait = true;
                    }
                }
            }
            return lst;
        }

        /// <summary>
        /// Méthode de génération des alertes sur les ECF non planifiées pour les compétences
        /// </summary>
        /// <returns>La liste d'Alertes</returns>
        public static List<Alerte> GenereAlertesECFNonPlanifiesPourCompetences()
        {
            List<Alerte> lst = new List<Alerte>();
            IQueryable<PlanningIndividuelFormation> query = EntityConnection.GetContext().PlanningIndividuelFormation;
            /* query = query.Where(it => it. >= DateTime.Now);*/
            List<PlanningIndividuelFormation> listePlanning = query.ToList();
            foreach (PlanningIndividuelFormation pif in listePlanning)
            {
                List<CompetenceParActivite> listeCompetenceParActivite = pif.Formation.GetListeCompetenceAPasser();
                foreach (CompetenceParActivite cpa in listeCompetenceParActivite)
                {
                    bool competenceTrouvee = false;
                    foreach (PlanningECFDetail ped in pif.PlanningECFDetail)
                    {
                        CompetenceParECF cpe = new CompetenceParECF();
                        cpe.IdCompetence = cpa.IdCompetence;
                        if (competenceTrouvee == false && ped.PlanningECF.ECF.CompetenceParECF.Contains(cpe, new CompetenceParECFComparerOnCompetence()))
                        {
                            competenceTrouvee = true;
                        }
                    }
                    if (competenceTrouvee == false)
                    {
                        Alerte a = new Alerte();
                        a.DateAlerte = DateTime.Now;
                        a.Echeance = DateTime.Now;
                        a.IdTypeAlerte = 1;
                        a.Actif = true;
                        a.Message = "Le stagiaire " + pif.Stagiaire.Prenom + " " + pif.Stagiaire.Nom + " n'a pas d'ECF planifié pour valider la compétence " + cpa.Competence.Libelle;
                        lst.Add(a);
                    }
                }
            }
            return lst;
        }

        /// <summary>
        /// Méthode de génération des alertes sur le délai de correction d'un ECF
        /// </summary>
        /// <returns>La liste d'Alertes</returns>
        public static List<Alerte> GenereAlertesDelaiCorrectionECF()
        {
            int nbJours = 5;
            List<Alerte> lst = new List<Alerte>();
            IQueryable<PlanningECFDetail> query = EntityConnection.GetContext().PlanningECFDetail;
            List<PlanningECFDetail> listePlanningECFDetail = query.ToList();
            foreach (PlanningECFDetail ped in listePlanningECFDetail)
            {
                bool ecfCorrige = true;
                foreach (ValidationCompetence vc in ped.ValidationCompetence)
                {
                    if (vc.Statut == null)
                    {
                        ecfCorrige = false;
                    }
                }
                if (ecfCorrige == false)
                {
                    TimeSpan ts = DateTime.Now - ped.PlanningECF.DateECF;
                    if (ts.Days > nbJours)
                    {
                        Alerte a = new Alerte();
                        a.DateAlerte = DateTime.Now;
                        a.Echeance = DateTime.Now;
                        a.IdTypeAlerte = 1;
                        a.Actif = true;
                        a.Message = "Le délai de correction (" + nbJours + " jours) pour l'ECF " + ped.PlanningECF.ECF.Libelle + " du stagiaire " + ped.PlanningIndividuelFormation.Stagiaire.Prenom + " " + ped.PlanningIndividuelFormation.Stagiaire.Nom + " à la date " + ped.PlanningECF.DateECF + " est dépassé.";
                        lst.Add(a);
                    }
                }
            }
            return lst;
        }

        /// <summary>
        /// Méthode de récupération de la liste des alertes actives depuis la date passée en paramètre.
        /// </summary>
        /// <param name="dateActuelle">Date de l'alerte</param>
        /// <param name="orderByDateAlerteAsc">Tri</param>
        /// <returns></returns>
        public List<Alerte> GetListeAlerteByDateAlerteSuperieureOuEgale(DateTime? dateActuelle, bool orderByDateAlerteAsc = false)
        {
            try
            {
                IQueryable<Alerte> query = EntityConnection.GetContext().Alerte;
                if (dateActuelle != null)
                {
                    query = query.Where(it => it.DateAlerte >= dateActuelle && it.Actif);
                }
                if (orderByDateAlerteAsc)
                {
                    query = query.OrderBy(it => it.DateAlerte);
                }
                else
                {
                    query = query.OrderByDescending(it => it.DateAlerte);
                }

                return query.ToList();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }


        /// <summary>
        /// Méthode d'ajout en base d'une nouvelle Alerte
        /// </summary>
        /// <param name="a">L'alerte à ajouter en base</param>
        /// <returns>L'alerte créée</returns>
        public static Alerte AjouterAlerte(Alerte a)
        {
            try
            {
                if (!EntityStateChecker.IsDetached(a))
                {
                    EntityConnection.GetContext().Alerte.Detach(a);
                }
                EntityConnection.GetContext().Alerte.AddObject(a);
                EntityConnection.GetContext().SaveChanges();
                return a;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// Méthode de suppression d'une alerte en base
        /// </summary>
        /// <param name="a">L'alerte à supprimer</param>
        public static void SupprimerAlerte(Alerte a)
        {
            try
            {
                if (a.EntityState == EntityState.Detached)
                {
                    EntityConnection.GetContext().Attach(a);
                }
                EntityConnection.GetContext().Alerte.DeleteObject(a);
                EntityConnection.GetContext().SaveChanges();
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }

        /// <summary>
        /// Méthode qui retourne une liste d'alertes filtrées par la date de rappel et le message
        /// </summary>
        /// <param name="message">Contenu du message sur lequel filtrer la requête</param>
        /// <param name="dateRappel">La date de rappel</param>
        /// <returns></returns>
        public static List<Alerte> GetListAlertesByMessageDate(string message, DateTime? dateRappel)
        {
            try
            {
                EntityConnection.Reinitialisation();
                EntityConnection.ClearEntities();
                IQueryable<Alerte> query = EntityConnection.GetContext().Alerte;

                // Filtre sur les alertes actives
                query = query.Where(it => it.Actif == true);
                
                // Filtre sur la date de l'alerte
                if (dateRappel != null)
                {
                    query = query.Where(it => it.DateAlerte >= dateRappel);
                }

                // Filtre sur le message
                if (message != null)
                {
                    query = query.Where(it => it.Message.Contains(message));
                }

                // Tri sur la date de l'alerte
                query.OrderBy(it => it.DateAlerte);
                return query.ToList();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
}
